package com.lcy.struct.bTreePlus.disk.core.engine;

import com.lcy.struct.bTreePlus.disk.core.BPlusTree;
import com.lcy.struct.bTreePlus.disk.core.BPlusTreeFactory;
import com.lcy.struct.bTreePlus.disk.index.BTreeIndex;
import com.lcy.struct.bTreePlus.disk.item.TreeNode;
import com.lcy.struct.bTreePlus.entity.BplusTreeTransactionInfo;
import com.lcy.struct.bTreePlus.property.BPlusFileInfo;

import java.util.HashMap;
import java.util.Map;

/**
 * @author lucongyang
 * @date Created in  17:16
 * @description 修改
 */
public class BPlusTreeUpdateEngine {
    private Map<Long, BPlusTree> needSerializeMap = new HashMap<>();

    public static BPlusTreeUpdateEngine getInstance() {
        return BPlusTreeUpdateEngineHandler.SINGLETON;
    }

    /**
     * 修改
     * 尽量保持不修改索引，效率会很高
     *
     * @param oldIndex 原索引,要修改数据的索引
     * @param treeNode   现节点（包括索引）
     */
    public void updateData(BTreeIndex oldIndex, TreeNode treeNode) {
        BPlusTree leaf = BPlusTreeFactory.findLeafOnDisk(oldIndex);
        if (leaf == null) {
            throw new RuntimeException("数据" + oldIndex.getIndexList() + "不存在，无法修改");
        }
        Comparable[] index = new Comparable[oldIndex.getIndexList().size()];
        index = oldIndex.getIndexList().toArray(index);
        Integer i = BPlusTreeFactory.findDataInLeaf(leaf, index);
        if (i == null) {
            throw new RuntimeException("数据" + oldIndex.getIndexList() + "不存在，无法修改");
        }

        // 如果修改涉及索引
        if (oldIndex.compare(treeNode.getIndex()) != 0) {
            try {
                // 做新增操作
                BPlusTreeAddEngine bPlusTreeAddEngine = BPlusTreeAddEngine.getInstance();
                bPlusTreeAddEngine.addNode(treeNode);
                BplusTreeTransactionInfo addTransactionInfo = bPlusTreeAddEngine.getSerializeCacheNeed();
                // 删除原先数据
                BPlusTreeDelEngine bPlusTreeDelEngine = BPlusTreeDelEngine.getInstance();
                bPlusTreeDelEngine.delData(index);
                BplusTreeTransactionInfo delTransactionInfo = bPlusTreeDelEngine.getSerializeCacheNeed();
                this.needSerializeMap.putAll(addTransactionInfo.getNeedSerializeMap());
                this.needSerializeMap.putAll(delTransactionInfo.getNeedSerializeMap());
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        // 如果不涉及修改索引操作（推荐）
        else {
            leaf.getDataList().set(i, treeNode.getData());
            addNeedSerialize(leaf);
        }
    }

    /**
     * 只能被消费一次
     *
     * @return 事务中需要持久化数据
     */
    public BplusTreeTransactionInfo getSerializeCacheNeed() {
        // todo 加锁
        BplusTreeTransactionInfo bplusTreeTransactionInfo = new BplusTreeTransactionInfo();
        bplusTreeTransactionInfo.setCount(BPlusFileInfo.getCount());
        bplusTreeTransactionInfo.setEndPosition(BPlusFileInfo.getEndPosition());
        bplusTreeTransactionInfo.setRootPosition(BPlusFileInfo.getRootPosition());

        bplusTreeTransactionInfo.setNeedSerializeMap(this.needSerializeMap);

        this.needSerializeMap = new HashMap<>();
        return bplusTreeTransactionInfo;
    }

    private static class BPlusTreeUpdateEngineHandler {
        private static final BPlusTreeUpdateEngine SINGLETON = new BPlusTreeUpdateEngine();
    }

    private void addNeedSerialize(BPlusTree... bPlusTrees) {
        for (BPlusTree bPlusTree : bPlusTrees) {
            needSerializeMap.put(bPlusTree.getPosition(), bPlusTree);
            BPlusTreeFactory.addCache(bPlusTree);
        }
    }
}
